﻿using System;
using System.Collections.Generic;
using Netbits.Common.Threading;

namespace Netbits.Common.Collections
{
	/// <summary>
	/// Represents a locked ListExtended class.
	/// </summary>
	/// <typeparam name="TItem">Type of the items</typeparam>
	public sealed class LockedListExtended<TItem> : ListExtended<TItem>
	{
		#region Private variables

		/// <summary>
		/// Lock instance
		/// </summary>
		readonly Lock _Lock;

		#endregion

		#region Constructor

		/// <summary>
		/// Create a new instance of ListExtended
		/// </summary>
		public LockedListExtended() : this( new Lock() )
		{
		}

		/// <summary>
		/// Create a new instance of ListExtended with specified Lock instance.
		/// </summary>
		/// <param name="Instance_">The Lock instance</param>
		public LockedListExtended( Lock Instance_ ) : base()
		{
			_Lock = Instance_;
		}

		/// <summary>
		/// Create a new instance of ListExtended with the specified initial capacity
		/// </summary>
		/// <param name="Capacity_">The number of items that the list can initially store</param>
		public LockedListExtended( int Capacity_ ) : this( new Lock(), Capacity_ )
		{
		}

		/// <summary>
		/// Create a new instance of ListExtended with the specified initial capacity and specified Lock instance.
		/// </summary>
		/// <param name="Capacity_">The number of items that the list can initially store</param>
		/// <param name="LockInstance_">The Lock instance</param>
		public LockedListExtended( Lock LockInstance_, int Capacity_ ) : base( Capacity_ )
		{
			_Lock = LockInstance_;
		}

		/// <summary>
		/// Create a new instance of ListExtended that contains items copied from the specified collection.
		/// </summary>
		/// <param name="Collection_">The collection whose items are copied</param>
		public LockedListExtended( IEnumerable<TItem> Collection_ ) : this( new Lock(), Collection_ )
		{
		}

		/// <summary>
		/// Create a new instance of ListExtended that contains items copied from the specified collection.
		/// </summary>
		/// <param name="Collection_">The collection whose items are copied</param>
		/// <param name="LockInstance_">The Lock instance</param>
		public LockedListExtended( Lock LockInstance_, IEnumerable<TItem> Collection_ ) : base( Collection_ )
		{
			_Lock = LockInstance_;
		}

		#endregion

		#region Overrides

		/// <summary>
		/// Function that would called if an item should be added to list.
		/// </summary>
		/// <param name="Item_">The item that should be added to list.</param>
		protected override void __AddItem( TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__AddItem( Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Function that checks the index is in range of list.
		/// </summary>
		/// <param name="Index_">The index to check</param>
		protected override void __CheckIndex( int Index_ )
		{
			try
			{
				_Lock.EnterReadLock();
				base.__CheckIndex( Index_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Function that would called if all items should be removed from the list.
		/// </summary>
		protected override void __ClearItems()
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__ClearItems();
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Function that would called if an item was accessed per indexer
		/// </summary>
		/// <param name="Index_">The index of the item that was accessed</param>
		/// <returns>The Item as the specified index-position</returns>
		protected override TItem __GetItem( int Index_ )
		{
			try
			{
				_Lock.EnterReadLock();
				return base.__GetItem( Index_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Function that would called if an item should be insert at the index-position
		/// </summary>
		/// <param name="Index_">The index of the item should be insert.</param>
		/// <param name="Item_">The item that should be insert at the specified index position</param>
		protected override void __InsertItem( int Index_, TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__InsertItem( Index_, Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Function that would called if an item would remove from index-position.
		/// </summary>
		/// <param name="Index_">The index of the item that would be removed from the list</param>
		protected override void __RemoveAtItem( int Index_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__RemoveAtItem( Index_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Function that would called if an item would remove from the list.
		/// </summary>
		/// <param name="Item_">The item that would remove from the list.</param>
		/// <returns>true if the item was successfully removed, otherwise false</returns>
		protected override bool __RemoveItem( TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				return base.__RemoveItem( Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Function that would called if the item at the index-position was changed
		/// </summary>
		/// <param name="Index_">The index of the item to be changed</param>
		/// <param name="Item_">The new item</param>
		protected override void __SetItem( int Index_, TItem Item_ )
		{
			try
			{
				_Lock.EnterWriteLock();
				base.__SetItem( Index_, Item_ );
			}
			finally
			{
				_Lock.ExitWriteLock();
			}
		}

		/// <summary>
		/// Determines whether the list contains the specified item.
		/// </summary>
		/// <param name="Item_">The item to locate in the list</param>
		/// <returns>true if the item is found in the list, otherwise false</returns>
		public override bool Contains( TItem Item_ )
		{
			try
			{
				_Lock.EnterReadLock();
				return base.Contains( Item_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Copies the entire list to a compatible one-dimensional array, starting at the specified index of the target array.
		/// </summary>
		/// <param name="Array_">The one-dimensional array that is the destination of the items copied from the list.</param>
		/// <param name="ArrayIndex_">The index in array at which copying begins</param>
		public override void CopyTo( TItem[] Array_, int ArrayIndex_ )
		{
			try
			{
				_Lock.EnterReadLock();
				base.CopyTo( Array_, ArrayIndex_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Get the number of items actually contained in the list.
		/// </summary>
		public override int Count
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return base.Count;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
		}

		/// <summary>
		/// Get the first item of the list. 
		/// </summary>
		public override TItem First
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return base.First;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
		}

		/// <summary>
		/// Get the enumerator that iterates through the list
		/// </summary>
		/// <returns>The new enumerator</returns>
		public override IEnumerator<TItem> GetEnumerator()
		{
			return new LockedEnumerator<TItem>( this, _Lock );
		}

		/// <summary>
		/// Get the index of the specified item
		/// </summary>
		/// <remarks>NULL items are not allowed! It throws an ArgumentNullException</remarks>
		/// <param name="Item_">The item to locate in the list</param>
		/// <returns>The index of the first occurrence of the item, otherwise -1</returns>
		public override int IndexOf( TItem Item_ )
		{
			try
			{
				_Lock.EnterReadLock();
				return base.IndexOf( Item_ );
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		/// <summary>
		/// Gets a value indicating whether the list is read-only. 
		/// In this implementation this property always return false.
		/// </summary>
		public override bool IsReadOnly
		{
			get
			{
				return base.IsReadOnly;
			}
		}

		/// <summary>
		/// Get the last item of the list
		/// </summary>
		public override TItem Last
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return base.Last;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
		}

		/// <summary>
		/// Get or set if the list use asynchrony events.
		/// </summary>
		public override bool UseAsyncEvents
		{
			get
			{
				try
				{
					_Lock.EnterReadLock();
					return base.UseAsyncEvents;
				}
				finally
				{
					_Lock.ExitReadLock();
				}
			}
			set
			{
				try
				{
					_Lock.EnterWriteLock();
					base.UseAsyncEvents = value;
				}
				finally
				{
					_Lock.ExitWriteLock();
				}
			}
		}

		/// <summary>
		/// Get or sets the maximum items that the list can contain.
		/// -1 for unlimited items.
		/// </summary>
		public override int MaxItems
		{
			get
			{
				return base.MaxItems;
			}
			set
			{
				System.Threading.Interlocked.Exchange( ref _MaxItems, value );
			}
		}

		/// <summary>
		/// Creates a copy of all items in the list in a new List
		/// </summary>
		/// <returns>The new list</returns>
		public override List<TItem> CopyToNewList()
		{
			try
			{
				_Lock.EnterReadLock();
				return base.CopyToNewList();
			}
			finally
			{
				_Lock.ExitReadLock();
			}
		}

		#endregion
	}
}
